﻿using Unity.Collections;
using Unity.Jobs;
using Unity.Mathematics;
using UnityEngine;
using UnityEngine.Rendering;

namespace Mars.GpuInstance
{
    public class GPUMeshRenderBatch : GPURenderBatch
    {
        public GPUMeshRenderBatch()
        {
            outputCount = new NativeArray<int>(1, Allocator.Persistent);
            outputIndex = new NativeList<int>(InstancerConstants.ADD_COUNT, Allocator.Persistent);
            boundVerts = new NativeArray<float4>(8, Allocator.Persistent);
        }

        public override void CopyAnimationData(in NativeList<float4> animatorControllerData,
            in NativeList<float4> animationData, NativeList<JobHandle> handles)
        {
        }

        public override JobHandle CalculateAnim(int frameRate, int textureSizeX, int totalBoneCount)
        {
            return default;
        }

        public override void UpdateAnimationBakeBuffer()
        {
        }

        public override void Dispose()
        {
            base.Dispose();
            renderMesh = null;
            renderMat = null;
        }

        public override void Draw(Bounds drawBounds, ShadowLod animatorShadowLod)
        {
            ShadowCastingMode shadowCastingMode = ShadowCastingMode.Off;
            if (animatorShadowLod == ShadowLod.FOLLOW_LOD)
            {
                shadowCastingMode = ShadowCastingMode.On;
            }
            DrawMeshInstanced(shadowCastingMode);
        }

        public override void DrawDebug(float sightDistance)
        {
        }

        public override void DrawShadows(Bounds drawBounds)
        {
            DrawMeshInstanced(ShadowCastingMode.ShadowsOnly);
        }
        
        #region 用DrawMeshInstanced绘制

        private void DrawMeshInstanced(ShadowCastingMode shadowCastingMode)
        {
            var instanceCount = GetInstanceCount();
            if (instanceCount <= 0)
            {
                return;
            }
            
            if (renderMesh == null)  //没有网格
            {
                return;
            }
            
            int batchCount = (int)math.ceil((float)instanceCount / (float)InstancerConstants.COUNT_PER_DRAW);
   
            for (int i = 0; i < batchCount; i++)
            {
                var srcIndex = i * InstancerConstants.COUNT_PER_DRAW;
                var copyCount = InstancerConstants.COUNT_PER_DRAW;
                if (i == (batchCount - 1))
                {
                    copyCount = instanceCount - i * InstancerConstants.COUNT_PER_DRAW;
                }

                MathUtil.Copy<float4, Vector4>(campData, srcIndex, campColorDatas, 0, copyCount);
                MathUtil.Copy<float4x4, Matrix4x4>(output, srcIndex, matrices, 0, copyCount);
                
                mpb.SetVectorArray(InstancerConstants.GPU_CampColorData, campColorDatas);
                DrawMeshInstanced(matrices,  copyCount, shadowCastingMode);
            }
        }
        
        #endregion
    }
}
